package br.edu.unifei.mestrado.mem.graph;

import java.util.HashMap;
import java.util.Iterator;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import br.edu.unifei.mestrado.commons.graph.GraphWrapper;
import br.edu.unifei.mestrado.commons.graph.NodeWrapper;
import br.edu.unifei.mestrado.commons.graph.RelationshipWrapper;
import edu.uci.ics.jung.graph.UndirectedSparseGraph;

public class Graph extends GraphWrapper {

	private Logger logger = LoggerFactory.getLogger(this.getClass());

	private HashMap<Long, Node> map = new HashMap<Long, Node>();

	private UndirectedSparseGraph<Node, Relationship> grafo;

	public Graph(Integer level, String graphFileName) {
		super(level, graphFileName);
		grafo = new UndirectedSparseGraph<Node, Relationship>();
	}

	@Override
	public void beginTransaction() {
	}

	@Override
	public void endTransaction() {
	}

	@Override
	public void finish() {
	}

	@Override
	public void shutdown() {
	}

	@Override
	public NodeMem createNode(long id, int weight) {
		Node node = map.get(id);
		if (node == null) {
			node = new Node(id, weight);
			map.put(id, node);
			grafo.addVertex(node);
			sizeNodes++;
		}
		return new NodeMem(node);
	}

	@Override
	public NodeWrapper getNode(long id) {
		Node node = map.get(id);
		if (node == null) {
			return null;
		}
		return new NodeMem(node);
	}

	@Override
	protected NodeWrapper getOrCreateNode(Long id, int weight) {
		return createNode(id, weight);
	}

	@Override
	public RelationshipWrapper createRelationship(long idEdge, int newWeight, long startNode, long endNode) {
		Node va = map.get(startNode);
		Node vb = map.get(endNode);
		Relationship aresta = new Relationship(idEdge, newWeight, va, vb);

		if (grafo.containsEdge(aresta)) {
			logger.warn("Aresta " + aresta + " jah existe no grafo");
		}

		va.addEdge(aresta);
		vb.addEdge(aresta);
		grafo.addEdge(aresta, aresta.getStartNode(), aresta.getEndNode());
		return new RelationshipMem(aresta);
	};

	@Override
	public Iterable<RelationshipWrapper> getAllEdges() {
		return new Iterable<RelationshipWrapper>() {
			@Override
			public Iterator<RelationshipWrapper> iterator() {
				return new Iterator<RelationshipWrapper>() {
					private Iterator<Relationship> edges = grafo.getEdges().iterator();

					@Override
					public RelationshipWrapper next() {
						Relationship edge = edges.next();
						return new RelationshipMem(edge);
					}

					@Override
					public boolean hasNext() {
						return edges.hasNext();
					}

					@Override
					public void remove() {
					}

				};
			}
		};
	}

	@Override
	public Iterable<NodeWrapper> getAllNodes() {

		return new Iterable<NodeWrapper>() {
			@Override
			public Iterator<NodeWrapper> iterator() {
				return new Iterator<NodeWrapper>() {
					private Iterator<Node> nodes = grafo.getVertices().iterator();

					@Override
					public NodeWrapper next() {
						Node node = nodes.next();
						return new NodeMem(node);
					}

					@Override
					public boolean hasNext() {
						return nodes.hasNext();
					}

					@Override
					public void remove() {
					}

				};
			}
		};
	}

	@Override
	public int getSizeNodes() {
		return grafo.getVertexCount();
	}

	@Override
	public RelationshipWrapper getArestaLinking(NodeWrapper va, NodeWrapper vb) {
		Node na = ((NodeMem) va).getInnerNode();
		Node nb = ((NodeMem) vb).getInnerNode();
		Relationship edge = grafo.findEdge(na, nb);
		if (edge == null) {
			return null;
		}

		RelationshipWrapper rel = new RelationshipMem(edge);
		return rel;
	}

	public UndirectedSparseGraph<Node, Relationship> getGraphToView() {
		return grafo;
	}
}
